// 为什么不能用dfs，因为国王的数量是确定的，并且每行可以有多个，所以可以有多个状态，dfs效率为2^(100)
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
using LL = long long;
const int N = 12, M = 1 << 10, K = 110; 
// int f[N][M][K]
LL f[N][K][M];
int n, m;
// f: 第i行状态为j，并且已经放置的国王数量为k的方案数量
// f[i][j][k] += f[i - 1][j1][k - num]
// dp顺序要满足拓扑序！！
vector<int> status;
vector<int> king_num;
vector<int> shift[M];

bool check(int i)
{
    return (i & (i << 1)) == 0;
}

int lowbit(int x) { return x & -x; }

int main()
{
    cin >> n >> m;
    // 预处理一行中合法的状态数量
    for(int i = 0; i < 1 << n; ++i)
    {
        // 对于一行中，不能有连续的1
        if(!check(i)) continue;
        int num = 0;
        LL tmp = i;
        while(tmp)
        {
            tmp -= lowbit(tmp);
            ++num;
        }
        status.push_back(i);
        king_num.push_back(num);
    }
    // 预处理每一个合法状态的下一个状态可以如何拼接
    size_t sz = status.size();
    for(int i = 0; i < sz; ++i)
        for(int j = 0; j < sz; ++j)
        {
            int up = status[i], down = status[j];
            if(up & down) continue;   /// 同一条直线上不能同时有元素
            if(!check(up | down)) continue;
            shift[i].push_back(j);
        }
        
    f[0][0][0] = 1;
    for(int i = 1; i <= n + 1; ++i)
        for(int j = 0; j <= m; ++j)
            for(int k = 0; k < status.size(); ++k)
            {
                //cout << k << ' ' << status[k] << endl;
                int a = status[k], num_a = king_num[k];
                for(auto e: shift[k])
                {
                    int b = status[e], num_b = king_num[e];
                    //cout << "---" << a << ' ' << num_a << endl;
                    //只有当前国王数足够放的下才放进去
                    if(j >= num_a)
                        f[i][j][a] += f[i - 1][j - num_a][b];
                }
            }
    cout << f[n + 1][m][0] << endl;
    return 0;
}